/**
 * 
 */
package it.unibo.refolding.pico;

import it.unibo.refolding.common.MyRuntimeException;

import java.lang.reflect.Field;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;

public class CommonRefoldingOptions {
  private final Option nanoDriverHostOption, nanoDriverPortOption, nanoDriverClassOption,
    nanoDriverDelayMillisOption, nanoDriverSleeperOption, captureDirectoryOption,
    targetDirectoryOption, sleepMillisOption, waitWhileEmptyMillisOption, forceRecordOption,
    debugOption, debugPatternOption;

  private CommonRefoldingOptions(Option nanoDriverHostOption, Option nanoDriverPortOption,
    Option nanoDriverClassOption, Option nanoDriverDelayMillisOption,
    Option nanoDriverSleeperOption, Option captureDirectoryOption, Option targetDirectoryOption,
    Option sleepMillisOption, Option waitWhileEmptyMillisOption, Option forceRecordOption,
    Option debugOption, Option debugPatternOption) {
    this.nanoDriverHostOption = nanoDriverHostOption;
    this.nanoDriverPortOption = nanoDriverPortOption;
    this.nanoDriverClassOption = nanoDriverClassOption;
    this.nanoDriverDelayMillisOption = nanoDriverDelayMillisOption;
    this.nanoDriverSleeperOption = nanoDriverSleeperOption;
    this.captureDirectoryOption = captureDirectoryOption;
    this.targetDirectoryOption = targetDirectoryOption;
    this.sleepMillisOption = sleepMillisOption;
    this.waitWhileEmptyMillisOption = waitWhileEmptyMillisOption;
    this.forceRecordOption = forceRecordOption;
    this.debugOption = debugOption;
    this.debugPatternOption = debugPatternOption;
  }

  public static CommonRefoldingOptions create() {
    Option nanoDriverClassOption = NanoDriverUtil.createNanoDriverClassOption();

    Option nanoDriverHostOption = NanoDriverUtil.createNanoDriverHostOption();
    Option nanoDriverPortOption = NanoDriverUtil.createNanoDriverPortOption();

    Option nanoDriverDelayMillisOption = new Option("nanoDriverDelayMillis", true, "");
    nanoDriverDelayMillisOption.setRequired(true);
    nanoDriverDelayMillisOption.setType(Double.TYPE);

    Option nanoDriverSleeperOption = new Option("nanoDriverSleeper", true, "");
    nanoDriverSleeperOption.setRequired(true);

    Option captureDirectoryOption = new Option(
      "captureDirectory", true, "filter only curves with at least this amount of peaks");
    captureDirectoryOption.setRequired(true);
    captureDirectoryOption.setType(String.class);

    Option targetDirectoryOption = new Option(
      "targetDirectory", true,
      "where to move captured files to keep capture directory mostly empty");
    targetDirectoryOption.setRequired(true);
    targetDirectoryOption.setType(String.class);

    Option sleepMillisOption = new Option(
      "sleepMillis", true, "how long to sleep when there are no new files");
    sleepMillisOption.setRequired(true);
    sleepMillisOption.setType(Long.TYPE);

    Option waitWhileEmptyMillisOption = new Option(
      "waitWhileEmptyMillis", true, "how long to sleep for an empty file to become non-empty");
    waitWhileEmptyMillisOption.setRequired(true);
    waitWhileEmptyMillisOption.setType(Long.TYPE);

    Option forceRecordOption = NanoDriverUtil.createForceRecordOption();

    Option debugOption = new Option(
      "debug", true, "Record the screen location even if already found in user preferences..");
    debugOption.setRequired(true);
    debugOption.setType(Boolean.TYPE);

    Option debugPatternOption = PicoUtil.createDebugPatternOption();

    Option throwOnMultipleFilesOption = new Option(
      "throwOnMultipleFiles", true,
      "Record the screen location even if already found in user preferences..");
    throwOnMultipleFilesOption.setRequired(true);
    throwOnMultipleFilesOption.setType(Boolean.TYPE);

    Option hoverNmOption = new Option(
      "hoverNm", true, "What distance above the surface we should hover.");
    hoverNmOption.setRequired(true);
    hoverNmOption.setType(Double.TYPE);

    return new CommonRefoldingOptions(
      nanoDriverHostOption, nanoDriverPortOption, nanoDriverClassOption,
      nanoDriverDelayMillisOption, nanoDriverSleeperOption, captureDirectoryOption,
      targetDirectoryOption, sleepMillisOption, waitWhileEmptyMillisOption, forceRecordOption,
      debugOption, debugPatternOption);
  }

  public void addTo(Options options) {
    for (Field field : getClass().getDeclaredFields()) {
      Option option;
      try {
        option = (Option) field.get(this);
      } catch (IllegalAccessException e) {
        throw new MyRuntimeException(e.getMessage(), e);
      }
      options.addOption(option);
    }
  }

  public Path getCaptureDirectory(CommandLine line) {
    return Paths.get(line.getOptionValue(captureDirectoryOption.getOpt()));
  }

  public Path getTargetDirectory(CommandLine line) {
    return Paths.get(line.getOptionValue(targetDirectoryOption.getOpt()));
  }

  public long getSleepMillis(CommandLine line) {
    return Long.parseLong(line.getOptionValue(sleepMillisOption.getOpt()));
  }

  public long getWaitWhileEmptyMillis(CommandLine line) {
    return Long.parseLong(line.getOptionValue(waitWhileEmptyMillisOption.getOpt()));
  }

  public String getNanoDriverClassname(CommandLine line) {
    return line.getOptionValue(nanoDriverClassOption.getOpt());
  }

  public String getNanoDriverHost(CommandLine line) {
    return line.getOptionValue(nanoDriverHostOption.getOpt());
  }

  public int getNanoDriverPort(CommandLine line) {
    return Integer.parseInt(line.getOptionValue(nanoDriverPortOption.getOpt()));
  }

  public boolean isForceRecord(CommandLine line) {
    return Boolean.parseBoolean(line.getOptionValue(forceRecordOption.getOpt()));
  }

  public boolean isDebug(CommandLine line) {
    return Boolean.parseBoolean(line.getOptionValue(debugOption.getOpt()));
  }

  public String getDebugPattern(CommandLine line) {
    return line.getOptionValue(debugPatternOption.getOpt());
  }

  public long getNanoDriverDelayMillis(CommandLine line) {
    return Long.parseLong(line.getOptionValue(nanoDriverDelayMillisOption.getOpt()));
  }

  public KnownSleepers getNanoDriverSleeper(CommandLine line) {
    return KnownSleepers.valueOf(line.getOptionValue(nanoDriverSleeperOption.getOpt()).toUpperCase(
      Locale.ROOT));
  }
}
